package cn.tsmchina.one.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;





import cn.tsmchina.one.util.alipay.security.RSASignature;
import cn.tsmchina.one.util.alipay.util.ParameterUtil;
import cn.tsmchina.one.util.alipay.util.StringUtil;
import cn.tsmchina.one.util.alipay.util.XMapUtil;
import cn.tsmchina.one.vo.alipay.DirectTradeCreateRes;
import cn.tsmchina.one.vo.alipay.ErrorCode;


public class TradeUtil
{
		private static  final String callbackUrl;

		private static final String notifyUrl;
		
		private static String merchantUrl;

		private static final String SEC_ID = "0001";
		
		private static final String REQ_URL = "https://wappaygw.alipay.com/service/rest.htm";
		
		private static String orderNo;
		
		static{
			callbackUrl = (String) ConfigUtil.get("callbackUrl");
			notifyUrl = (String) ConfigUtil.get("notifyUrl");
			merchantUrl = (String) ConfigUtil.get("merchantUrl");
		}

		public static void trade(HttpServletRequest request, HttpServletResponse response, String productName,String totalPrice, String orderId) throws IOException
		{
			orderNo = orderId;
			Map<String, String> reqParams = prepareTradeRequestParamsMap(request,productName,totalPrice);
			String signAlgo = SEC_ID;
			String reqUrl = REQ_URL;
			String sign = sign(reqParams, signAlgo, PartnerConfig.RSA_PRIVATE);
			reqParams.put("sign", sign);
			ResponseResult resResult = new ResponseResult();
			String businessResult = "";
			try
			{
				resResult = send(reqParams, reqUrl, signAlgo);
			} catch (Exception e1)
			{ 
				e1.printStackTrace();
			}
			if (resResult.isSuccess())
			{
				businessResult = resResult.getBusinessResult();
			} else
			{
				return;
			}
			DirectTradeCreateRes directTradeCreateRes = null;
			XMapUtil.register(DirectTradeCreateRes.class);
			try
			{
				directTradeCreateRes = (DirectTradeCreateRes) XMapUtil.load(new ByteArrayInputStream(businessResult.getBytes("UTF-8")));
			}catch (Exception e)
			{
				
			}
			String requestToken = directTradeCreateRes.getRequestToken();
			System.out.println("Token:" + requestToken);
			Map<String, String> authParams = prepareAuthParamsMap(request,requestToken);
			String authSign = sign(authParams, signAlgo, PartnerConfig.RSA_PRIVATE);
			authParams.put("sign", authSign);
			String redirectURL = "";
			try
			{
				redirectURL = getRedirectUrl(authParams, reqUrl);
				System.out.println("authAndExecute URL:" + redirectURL);
			} catch (Exception e)
			{
				e.printStackTrace();
			}
			if (StringUtil.isNotBlank(redirectURL))
			{
				response.sendRedirect(redirectURL);
				return;
			}
		}

		/**
		 * 服务需要的参数
		 * @author YUE
		 * @date 2013-6-28 下午8:10:53
		 * @param request
		 * @param subject 
		 * @param totalFee 
		 * @return
		 * @throws UnsupportedEncodingException
		 */
		private static Map<String, String> prepareTradeRequestParamsMap(HttpServletRequest request, String subject, String totalFee) throws UnsupportedEncodingException
		{
			Map<String, String> requestParams = new HashMap<String, String>();
			request.setCharacterEncoding("utf-8");
			String sellerAccountName = PartnerConfig.SELLER;
			String reqData = "<direct_trade_create_req>" + "<subject>" + subject
					+ "</subject><out_trade_no>" + orderNo
					+ "</out_trade_no><total_fee>" + totalFee
					+ "</total_fee><seller_account_name>" + sellerAccountName
					+ "</seller_account_name><notify_url>" + notifyUrl
					+ "</notify_url><call_back_url>" + callbackUrl
					+ "</call_back_url><merchant_url>" + merchantUrl
					+ "</merchant_url>";
			reqData = reqData + "</direct_trade_create_req>";
			requestParams.put("req_data", reqData);
			requestParams.put("req_id", System.currentTimeMillis() + "");
			requestParams.putAll(prepareCommonParams(request));
			return requestParams;
		}

		/**
		 * 准备通用参数
		 * 
		 * @author YUE
		 * @date 2013-6-28 下午8:12:56
		 * @param request
		 * @return
		 */
		private static Map<String, String> prepareCommonParams(HttpServletRequest request)
		{
			Map<String, String> commonParams = new HashMap<String, String>();
			commonParams.put("service", "alipay.wap.trade.create.direct");
			commonParams.put("sec_id", SEC_ID);
			commonParams.put("partner", PartnerConfig.PARTNER);
			commonParams.put("call_back_url", callbackUrl);
			commonParams.put("format", "xml");
			commonParams.put("v", "2.0");
			return commonParams;
		}

		/**
		 * 准备alipay.wap.auth.authAndExecute服务的参数
		 * @param request
		 * @param requestToken
		 * @return
		 */
		private static Map<String, String> prepareAuthParamsMap(HttpServletRequest request, String requestToken)
		{
			Map<String, String> requestParams = new HashMap<String, String>();
			String reqData = "<auth_and_execute_req><request_token>" + requestToken
					+ "</request_token></auth_and_execute_req>";
			requestParams.put("req_data", reqData);
			requestParams.putAll(prepareCommonParams(request));
			// 支付成功跳转链接

			requestParams.put("call_back_url", callbackUrl);
			requestParams.put("service", "alipay.wap.auth.authAndExecute");
			return requestParams;
		}

		/**
		 * 对参数进行签名
		 * @param reqParams
		 * @return
		 */
		private static String sign(Map<String, String> reqParams, String signAlgo,String key)
		{

			String signData = ParameterUtil.getSignData(reqParams);
			System.out.println("Unsigned Data:" + signData);
			String sign = "";
			try
			{
				sign = RSASignature.sign(signData, key, "");
			} catch (Exception e1)
			{
				e1.printStackTrace();
			}
			return sign;
		}

		/**
		 * 调用alipay.wap.auth.authAndExecute服务的时候需要跳转到支付宝的页面，组装跳转url
		 * @param reqParams
		 * @return
		 * @throws Exception
		 */
		private static String getRedirectUrl(Map<String, String> reqParams, String reqUrl) throws Exception
		{
			String redirectUrl = reqUrl + "?";
			redirectUrl = redirectUrl + ParameterUtil.mapToUrl(reqParams);
			return redirectUrl;
		}

		/**
		 * 调用支付宝开放平台的服务
		 * 
		 * @param reqParams
		 *            请求参数
		 * @return
		 * @throws Exception
		 */
		private static ResponseResult send(Map<String, String> reqParams, String reqUrl, String secId) throws Exception
		{
			String response = "";
			String invokeUrl = reqUrl + "?";
			URL serverUrl = new URL(invokeUrl);
			HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();

			conn.setRequestMethod("POST");
			conn.setDoOutput(true);
			conn.connect();
			String params = ParameterUtil.mapToUrl(reqParams);
			System.out.println("Request Token:"+ URLDecoder.decode(params, "utf-8"));
			conn.getOutputStream().write(params.getBytes());
			InputStream is = (InputStream) conn.getInputStream();

			BufferedReader in = new BufferedReader(new InputStreamReader(is));
			StringBuffer buffer = new StringBuffer();
			String line = "";
			while ((line = in.readLine()) != null)
			{
				buffer.append(line);
			}
			response = URLDecoder.decode(buffer.toString(), "utf-8");
			System.out.println("Response:" + response);
			conn.disconnect();
			return praseResult(response, secId);
		}

		/**
		 * 解析支付宝返回的结果
		 * 
		 * @param response
		 * @return
		 * @throws Exception
		 */
		private static ResponseResult praseResult(String response, String secId)throws Exception
		{
			// 调用成功
			HashMap<String, String> resMap = new HashMap<String, String>();
			String v = ParameterUtil.getParameter(response, "v");
			String service = ParameterUtil.getParameter(response, "service");
			String partner = ParameterUtil.getParameter(response, "partner");
			String sign = ParameterUtil.getParameter(response, "sign");
			String reqId = ParameterUtil.getParameter(response, "req_id");
			resMap.put("v", v);
			resMap.put("service", service);
			resMap.put("partner", partner);
			resMap.put("sec_id", secId);
			resMap.put("req_id", reqId);
			String businessResult = "";
			ResponseResult result = new ResponseResult();
			System.out.println("Token Result:" + response);
			if (response.contains("<err>"))
			{
				result.setSuccess(false);
				businessResult = ParameterUtil.getParameter(response, "res_error");

				// 转换错误信息
				XMapUtil.register(ErrorCode.class);
				ErrorCode errorCode = (ErrorCode) XMapUtil.load(new ByteArrayInputStream(businessResult.getBytes("UTF-8")));
				result.setErrorMessage(errorCode);

				resMap.put("res_error",
						ParameterUtil.getParameter(response, "res_error"));
			} else
			{
				businessResult = ParameterUtil.getParameter(response, "res_data");
				result.setSuccess(true);
				// 对返回的res_data数据先用商户私钥解密
				String resData = RSASignature.decrypt(businessResult,PartnerConfig.RSA_PRIVATE);
				result.setBusinessResult(resData);
				resMap.put("res_data", resData);
			}
			// 获取待签名数据
			String verifyData = ParameterUtil.getSignData(resMap);
			System.out.println("verifyData:" + verifyData);
			// 对待签名数据使用支付宝公钥验签名
			boolean verified = RSASignature.doCheck(verifyData, sign,PartnerConfig.RSA_ALIPAY_PUBLIC, "");
			if (!verified)
			{
				throw new Exception("验证签名失败");
			}
			return result;
		}
	}
